/**
 * 统一的Token管理工具
 * 避免在多个地方重复操作localStorage
 */
import axios from 'axios';
import constant from './constant';

// Token键名常量
export const TOKEN_KEYS = {
  AUTH_TOKEN: 'auth_token',
  REFRESH_TOKEN: 'refresh_token'
} as const;

/**
 * Token管理类
 */
export class TokenManager {
  private static instance: TokenManager;
  private isRefreshing = false;
  private refreshSubscribers: Array<(token: string) => void> = [];
  private refreshInterval: number | null = null;
  
  // 私有构造函数，确保单例模式
  private constructor() {}
  
  /**
   * 获取单例实例
   */
  public static getInstance(): TokenManager {
    if (!TokenManager.instance) {
      TokenManager.instance = new TokenManager();
    }
    return TokenManager.instance;
  }

  /**
   * 从Cookie读取token（Cookie由后端设置，HttpOnly）
   * 注意：HttpOnly cookie无法通过JavaScript直接读取，需要后端API返回
   */
  private static getTokenFromCookie(name: string): string | null {
    // HttpOnly cookie无法通过document.cookie读取
    // 需要通过后端API或服务器端读取
    // 这里返回null，实际token会通过后端验证接口返回
    return null;
  }

  /**
   * 获取认证token (Access Token)
   * 优先从localStorage，如果localStorage没有则尝试从Cookie读取
   * 注意：HttpOnly cookie无法通过JavaScript直接读取，需要通过后端API
   */
  static getAuthToken(): string | null {
    // 优先从localStorage读取
    const localToken = localStorage.getItem(TOKEN_KEYS.AUTH_TOKEN);
    if (localToken) {
      return localToken;
    }
    
    // 注意：由于后端设置了HttpOnly cookie，前端无法直接读取
    // 需要通过后端API验证接口获取token信息
    // 或者后端在响应头中返回token
    return null;
  }

  /**
   * 获取刷新token (Refresh Token)
   */
  static getRefreshToken(): string | null {
    return localStorage.getItem(TOKEN_KEYS.REFRESH_TOKEN);
  }

  /**
   * 设置认证token (Access Token)
   */
  static setAuthToken(token: string): void {
    localStorage.setItem(TOKEN_KEYS.AUTH_TOKEN, token);
  }

  /**
   * 设置刷新token (Refresh Token)
   */
  static setRefreshToken(token: string): void {
    localStorage.setItem(TOKEN_KEYS.REFRESH_TOKEN, token);
  }

  /**
   * 设置所有token
   */
  static setTokens(authToken: string, refreshToken: string): void {
    this.setAuthToken(authToken);
    this.setRefreshToken(refreshToken);
  }

  /**
   * 清除所有token - 已废弃，请使用clearAuth
   * @deprecated 使用clearAuth替代
   */
  static clearTokens(): void {
    this.clearAuth();
  }

  /**
   * 清除认证相关的所有token
   * 符合代码准则的标准方法
   */
  static clearAuth(): void {
    localStorage.removeItem(TOKEN_KEYS.AUTH_TOKEN);
    localStorage.removeItem(TOKEN_KEYS.REFRESH_TOKEN);
    
    // 停止刷新定时器
    TokenManager.getInstance().stopRefreshTimer();
  }

  /**
   * 检查是否已认证
   */
  static isAuthenticated(): boolean {
    const authToken = this.getAuthToken();
    return !!authToken && authToken.length > 0;
  }

  /**
   * 获取所有token信息
   */
  static getTokenInfo() {
    const token = this.getAuthToken();
    let tokenPayload = null;
    let expiresAt = null;
    
    if (token) {
      try {
        // 解析JWT token获取payload部分
        const base64Url = token.split('.')[1];
        const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
        tokenPayload = JSON.parse(window.atob(base64));
        
        // 获取过期时间（exp是Unix时间戳，单位为秒）
        if (tokenPayload.exp) {
          expiresAt = tokenPayload.exp * 1000; // 转换为毫秒
        }
      } catch (e) {
        console.error('解析token失败', e);
      }
    }
    
    return {
      authToken: this.getAuthToken(),
      refreshToken: this.getRefreshToken(),
      isAuthenticated: this.isAuthenticated(),
      expiresAt: expiresAt,
      payload: tokenPayload
    };
  }

  /**
   * 检查Access Token是否过期
   * @returns true表示已过期，false表示未过期
   */
  static isTokenExpired(): boolean {
    const tokenInfo = this.getTokenInfo();
    if (!tokenInfo.expiresAt) return true;
    
    // 提前5秒检查过期，留出网络请求时间
    return Date.now() > (tokenInfo.expiresAt - 5000);
  }

  /**
   * 检查Access Token是否即将过期
   * @param thresholdSeconds 即将过期的阈值（秒）
   * @returns true表示即将过期，false表示不会很快过期
   */
  static isTokenExpiringSoon(thresholdSeconds: number = 60): boolean {
    const tokenInfo = this.getTokenInfo();
    if (!tokenInfo.expiresAt) return true;
    
    return Date.now() > (tokenInfo.expiresAt - (thresholdSeconds * 1000));
  }
  
  /**
   * 初始化token刷新服务
   */
  public init(): void {
    // 清除可能存在的旧定时器
    this.stopRefreshTimer();
    
    // 设置定时检查，每30秒检查一次token是否即将过期
    this.refreshInterval = window.setInterval(() => {
      this.checkAndRefreshToken();
    }, 30000); // 30秒检查一次
  }
  
  /**
   * 停止刷新定时器
   */
  public stopRefreshTimer(): void {
    if (this.refreshInterval !== null) {
      window.clearInterval(this.refreshInterval);
      this.refreshInterval = null;
    }
  }
  
  /**
   * 检查并刷新token
   */
  public async checkAndRefreshToken(): Promise<void> {
    // 如果没有token或者正在刷新中，则跳过
    if (!TokenManager.getAuthToken() || this.isRefreshing) {
      return;
    }
    
    // 如果Access Token即将过期（60秒内），则使用Refresh Token刷新
    if (TokenManager.isTokenExpiringSoon(60)) {
      await this.refreshToken();
    }
  }
  
  /**
   * 使用Refresh Token刷新Access Token
   * 注意：此操作通常只会更新Access Token，Refresh Token保持不变
   * 除非后端同时返回了新的Refresh Token
   */
  public async refreshToken(): Promise<string | null> {
    // 如果已经在刷新中，则返回一个Promise
    if (this.isRefreshing) {
      return new Promise<string>((resolve) => {
        this.addRefreshSubscriber((token: string) => {
          resolve(token);
        });
      });
    }
    
    const refreshToken = TokenManager.getRefreshToken();
    if (!refreshToken) {
      console.error('[TokenManager] 没有可用的Refresh Token');
      return null;
    }
    
    this.isRefreshing = true;
    
    try {
      // 直接使用原始axios避免循环依赖，因为request.ts依赖于TokenManager
      const response = await axios.post(`${constant.baseURL}/auth-center/refresh-token`, {
        refreshToken
      });
      
      if (response.data.code === 200 && response.data.data) {
        const { accessToken } = response.data.data;
        
        // 更新Access Token
        TokenManager.setAuthToken(accessToken);
        
        // 如果后端同时返回了新的Refresh Token，也一并更新
        if (response.data.data.refreshToken) {
          TokenManager.setRefreshToken(response.data.data.refreshToken);
        }
        
        // 通知所有等待的订阅者
        this.onRefreshed(accessToken);
        return accessToken;
      }
      
      console.error('[TokenManager] Access Token刷新失败：服务器响应无效');
      return null;
    } catch (error) {
      console.error('[TokenManager] Access Token刷新失败', error);
      return null;
    } finally {
      this.isRefreshing = false;
    }
  }
  
  /**
   * 添加刷新订阅者
   * @param callback 回调函数
   */
  public addRefreshSubscriber(callback: (token: string) => void): void {
    this.refreshSubscribers.push(callback);
  }
  
  /**
   * 通知所有订阅者token已刷新
   * @param token 新的token
   */
  public onRefreshed(token: string): void {
    this.refreshSubscribers.forEach(callback => callback(token));
    this.refreshSubscribers = [];
  }
  
  /**
   * 判断是否正在刷新token
   */
  public isRefreshingToken(): boolean {
    return this.isRefreshing;
  }
}

// 导出默认实例
export default TokenManager; 